﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml;
using System.Xml.Linq;

namespace 战棋模拟器
{//遗留问题：
    //1.目前瑞文，卡德加，猎马人，胖头鱼需要硬编码，但暂时没办法更好处理。因为事实上暴雪就是特殊处理的：
        //以下解释这四张牌

        //(1)暴雪曾经修改过瑞文的判定，让瑞文和金瑞文不再共享加成，并且同类也不共享加成
        //(2)暴雪在战棋模式中重做过卡德加，证据为：目前卡德加无法正确实现复生。（已经正确实现这个bug以和游戏一致）
        //(3)对于猎马人就不谈了，肯定得特殊处理。除非将来有很多的挑选攻击对象的随从，将会用策略模式来改写。
        //(4)对于胖头鱼也是暴雪特殊处理的。证据为：接受aoe破盾后会补盾这个现象。虽然名义上是同时但胖头鱼的判定却在这一事件发生之后结算，这与炉石正常的顺序并不相同。
    
    //2.已经增加aoe对于胖头鱼，安保钴制等的正确处理
    //3.已经增加二王的特殊效果的支持，支持所谓的“受伤”判定，对将来其他生命类光环的正确实现也有好处。
    //4.调用spawn时考虑改写成随从触发，参数变为随从和随从，召唤者和被召唤者，以减少卡德加的代码量。
    class Program
    {
        static void Main(string[] args)
        {
            //experiment0();
            do
            {
                experimentfromxml();
                Console.WriteLine("按下R重新测试，按下其他键退出\n");
            }
            while (Console.ReadKey().Key == ConsoleKey.R);
                
            //test19();
        }
        public static void experimentfromxml()
        {
            Pool u = new Pool();
            Pool d = new Pool();
            XDocument document = XDocument.Load("BoardConfig.xml");
            XElement root = document.Root;
            XElement uppool = root.Element("uppool");
            IEnumerable<XElement> upms = uppool.Elements();
            int i = 0;
            foreach (XElement sn in upms)
            {
                string tryname = sn.Element("name").Value;
                if (tryname == "")
                    continue;
                string s = "战棋模拟器." + tryname;
                Type t = Type.GetType(s);
                Minion m = (Minion)t.Assembly.CreateInstance(s);
                string atk = sn.Element("attack").Value;
                if (atk != "")
                    m.Attack = int.Parse(atk);
                string hlt = sn.Element("health").Value;
                if (hlt != "")
                    m.Health = int.Parse(hlt);
                string desc = sn.Element("skills").Value;
                m.SetValue(m.Attack, m.Health, desc);
                i++;
                if (i > 7)
                    throw new Exception("随从数过多");
                u.AddMinion(m);
            }
            XElement downpool = root.Element("downpool");
            IEnumerable<XElement> dpms = downpool.Elements();
            i = 0;
            foreach (XElement sn in dpms)
            {
                string tryname = sn.Element("name").Value;
                if (tryname == "")
                    continue;
                string s = "战棋模拟器." + tryname;
                Type t = Type.GetType(s);
                Minion m = (Minion)t.Assembly.CreateInstance(s);
                string atk = sn.Element("attack").Value;
                if (atk != "")
                    m.Attack = int.Parse(atk);
                string hlt = sn.Element("health").Value;
                if (hlt != "")
                    m.Health = int.Parse(hlt);
                string desc = sn.Element("skills").Value;
                m.SetValue(m.Attack, m.Health, desc);
                i++;
                if (i > 7)
                    throw new Exception("随从数过多");
                d.AddMinion(m);
            }
            bool details = root.Element("details").Value == "true";
            bool deathwing = root.Element("deathwing").Value == "true";
            Board myboard = new Board(details, d, u);
            myboard.DeathWing = deathwing;
            if (details)
            {
                myboard.Execute(myboard.DirDetermine());
            }
            else
            {
                myboard.Experiment();
            }
        }



        //实打实的实验
        public static void experiment0()
        {
            Pool u = new Pool(new 洞穴多头蛇(), new 爆爆机器人_金色(), new 鲭鱼圣者(), new 无私的英雄(), new 青铜守卫(), new 光牙执行者_金色(), new 攻城恶魔());
            Pool d = new Pool(new 死神4000型(), new 鲭鱼圣者(), new 钴制卫士_金色(), new 机械蛋_金色(), new 坎格尔的学徒(), new 阴森巨蟒(), new 瑞文戴尔男爵());
            u.places[0].SetValue(43, 38);
            u.places[1].SetValue(47, 30, "圣盾嘲讽");
            u.places[2].SetValue(26, 18, "剧毒圣盾");
            u.places[4].SetValue(44, 26, "圣盾复生");
            u.places[5].SetValue(7, 7, "嘲讽");
            u.places[6].SetValue(45, 29);
            d.places[0].SetValue(19, 18, "圣盾嘲讽");
            d.places[1].SetValue(13, 9, "圣盾");
            d.places[2].SetValue(20, 6, "圣盾");
            d.places[3].SetValue(6, 10);
            d.places[5].SetValue(11, 11);
            Board myBoard = new Board(true, d, u);
            myBoard.Experiment();                
            Console.ReadKey();
        }



        //测试0攻随从的情况以及有嘲讽的0攻随从的情况能否正确选择攻击者和被攻击者，以及跳过回合以及判定胜负
        public static void test3()
        {
            Pool u = new Pool(new 机械蛋(), new 机械蛋(), new 机械蛋());
            Pool d = new Pool(new 机械蛋(), new Minion());
            u.places[0].Skills[2] = true;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(true);
            Console.ReadKey();
            
        }


        //用来测试光环类随从是否能正确迭代
        public static void test4()
        {
            Pool u = new Pool(new 老瞎眼(), new 老瞎眼(), new 恐狼前锋(), new 鱼人领军(), new 鱼人领军());
            Pool d = new Pool(new 恐狼前锋(), new 恐狼前锋(),new 鱼人招潮者(), new 鱼人猎潮者(), new 恐狼前锋(), new 鱼人领军(), new 鱼人领军());
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        public static void test4_1()
        {
            Pool u = new Pool(new 载人收割机(), new 载人收割机(), new 载人收割机());
            Pool d = new Pool(new 载人收割机(), new 恐狼前锋());
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }

        //用来测试死亡结算顺序是否真实地与游戏一致
        public static void test5()
        {
            Pool u = new Pool(new 爆爆机器人(), new 爆爆机器人(), new 爆爆机器人(), new 爆爆机器人(), new 爆爆机器人(), new 爆爆机器人(), new 爆爆机器人());
            Pool d = new Pool(new 爆爆机器人(), new 爆爆机器人(), new 爆爆机器人(), new 爆爆机器人(), new 爆爆机器人(), new 爆爆机器人(), new 爆爆机器人());
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //测试圣盾嘲讽的结算
        public static void test0()
        {
            Pool u = new Pool(new 正义保护者(), new 正义保护者(), new 正义保护者(), new 正义保护者(), new 正义保护者(), new 正义保护者(), new 正义保护者());
            Pool d = new Pool(new 正义保护者(), new 正义保护者(), new 正义保护者(), new 正义保护者(), new 正义保护者(), new 正义保护者(), new 正义保护者());
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //solo!
        public static void test1()
        {
            Pool u = new Pool(new 阴森巨蟒_金色());
            Pool d = new Pool(new 阴森巨蟒_金色());
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //鼠 年 大 礼 包
        //以及死亡之翼模式
        public static void test2()
        {
            Pool u = new Pool(new 恐狼前锋(), new 瘟疫鼠群());
            Pool d = new Pool(new 瘟疫鼠群(),new 恐狼前锋());
            Board myBoard = new Board(true, d, u);
            myBoard.DeathWing = true;
            myBoard.Execute(false);
            Console.ReadKey();
        }

        //测试：１.添加在末尾的随从是否正确影响攻击序列
        //　　　２.比斯巨兽能否正确受到己方卡德加而非对方卡德加的影响
        public static void test6()
        {
            Pool u = new Pool(new 比斯巨兽(), new 比斯巨兽());
            Pool d = new Pool(new 瘟疫鼠群(), new 比斯巨兽(), new 食腐土狼());
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //这个问题测试小鬼首领能否正确判定受到伤害
        public static void test7()
        {
            Pool u = new Pool(new 机械蛋(), new 机械蛋(), new 机械蛋(), new 机械蛋(), new 机械蛋(), new 机械蛋(), new 机械蛋());
            Pool d = new Pool(new 无私的英雄(), new 小鬼首领(), new 小鬼首领(), new 小鬼首领(), new 小鬼首领(), new 小鬼首领(), new 小鬼首领());
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //卡德加能测试一年
        //这个用来看给对方召唤随从的时候己方双卡德加的发动，理论上应当是在队尾，队尾＋１，队尾＋２，队尾＋１的位置召唤。共４个
        //第二个卡德加召唤的第一个随从是第一个卡德加召唤的衍生随从，由于深度优先的规则，所以先触发，位置＋２.
        public static void test8()
        {
            Pool u = new Pool(new 比斯巨兽(), new 卡德加(), new 卡德加());
            Pool d = new Pool(new 比斯巨兽(), new 卡德加(), new 卡德加());
            u.places[0].Skills[2] = true;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }

        //可以预测一下，一个1攻的鼠群本来产生一个1/1的狂鼠，被族群领袖buff到4/1，被buff后的被卡德加复制，复制品放在原品的后面，所以应当是4/1,7/1.
        //2攻的鼠群就是将这个过程重复两次，也就是４，７，４，７.
        //如果1攻的鼠群被２个卡德加和族群领袖buff,则应当像上个测试样例一样，位置是１，２，３，２，攻击力是４，７，７,１０（按位置，按时间是４，７，１０，７）.
        public static void test8_1()
        {
            Pool u = new Pool(new 瘟疫鼠群(), new 卡德加(), new 族群领袖());
            Pool d = new Pool(new 瘟疫鼠群(), new 卡德加(), new 卡德加(), new 族群领袖());
            u.places[0].Skills[2] = true;
            u.places[0].Health = 1;
            d.places[0].Attack = 1;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //测试金卡德加，以及金卡德加和普通卡德加的叠加。符合预期。
        public static void test8_2()
        {
            Pool u = new Pool(new 瘟疫鼠群(), new 卡德加_金色(), new 族群领袖());
            Pool d = new Pool(new 瘟疫鼠群(), new 卡德加(), new 卡德加_金色(), new 族群领袖());
            u.places[0].Skills[2] = true;
            u.places[0].Health = 1;
            d.places[0].Attack = 1;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //炉石里不同卡德加的排列不同会造成结果不同，很多人都知道要把金卡德加放在后面，这里可以进行测试
        public static void test8_3()
        {
            Pool u = new Pool(new 比斯巨兽());



            //这是普通卡德加在前的代码，1+2^0+2^(1+1)=6个
            //Pool d = new Pool(new 比斯巨兽(), new 卡德加(), new 卡德加_金色());


            //这是金色卡德加在前的代码，1+2^(0+1)+2^1=5个
            Pool d = new Pool(new 比斯巨兽(), new 卡德加_金色(), new 卡德加());


            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        
        //测试复生和卡德加的效果
        public static void test8_4()
        {
            Pool u = new Pool(new 青铜守卫(), new 卡德加(), new 青铜守卫());
            Pool d = new Pool(new 虚空领主());
            u.places[1].Health = 9;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(true);
            Console.ReadKey();
        }


        //测试狂战斧是否正确结算（炉石里是1对左中右按顺序造成伤害，2自身受到伤害，1和2的顺序不定，按照主玩家排序来结算）
        public static void test9()
        {
            Pool u = new Pool(new 爆爆机器人(), new 机械蛋(), new 比斯巨兽());
            Pool d = new Pool(new 洞穴多头蛇()/*, new 机械蛋(), new 机械蛋(), new 机械蛋()*/);
            u.places[1].Skills[2] = true;
            d.places[0].Attack = 5;
            d.places[0].Health = 7;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //测试瑞文戴尔男爵
        public static void test10()
        {
            Pool u = new Pool(new 机械蛋(), new 比斯巨兽(), new 瑞文戴尔男爵_金色());
            Pool d = new Pool(new 爆爆机器人(), new 瑞文戴尔男爵(), new 瑞文戴尔男爵_金色(), new 瑞文戴尔男爵());
            u.places[0].Skills[2] = true;
            u.places[0].Attack = 2;
            d.places[0].Attack = 5;
            u.places[1].Health = 1;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //测试超杀
        //全体满员的情况。按照炉石的规则先结算超杀再结算死亡再结算亡语，可以预测芬克恩霍尔可以正确被产生（因为在死亡之后，有格子），而第一只小恐龙不会出生，因为发生在死亡之前
        public static void test11()
        {
            Pool u = new Pool(new 比斯巨兽(), new 比斯巨兽(), new 比斯巨兽(), new 比斯巨兽(), new 比斯巨兽(), new 比斯巨兽(), new 比斯巨兽());
            Pool d = new Pool(new 铁皮恐角龙(), new 铁皮恐角龙(), new 铁皮恐角龙(), new 铁皮恐角龙(), new 铁皮恐角龙(), new 铁皮恐角龙(), new 铁皮恐角龙());
            foreach (Minion m in u.places)
                m.Health--;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //用来测试猎马人，金猎马人，风怒和超级风怒
        public static void test12()
        {
            Pool u = new Pool(new 机械蛋(), new 机械蛋(), new 机械蛋(), new 机械蛋(),new 机械袋鼠(), new 虚空领主(), new 虚空领主());
            Pool d = new Pool(new 扎普斯里维克(), new 扎普斯里维克_金色(), new 扎普斯里维克(), new 扎普斯里维克(), new 扎普斯里维克(), new 扎普斯里维克(), new 扎普斯里维克());
            foreach (Minion m in u.places)
                m.Health=15;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //用来测试坎格尔的学徒，能否正确复活未经buff版本的机械
        //复活后生成未经buff过的牌，并且不影响坟场，第一次复活两个，第二次复活时应当复活1234（而不是3456）
        public static void test13()
        {
            Pool u = new Pool(new 鱼人斥候());
            Pool d = new Pool(new 机械袋鼠_金色(), new 机械袋鼠(), new 爆爆机器人(), new 百变泽鲁斯(), new 闹闹机器人(), new 坎格尔的学徒(), new 坎格尔的学徒_金色());
            for (int i = 0; i < 5; i++)
            {
                d.places[i].Skills[2] = true;
                d.places[i].Health++;//这里代表buff过
            }
            u.places[0].Health = 200;
            u.places[0].Skills[0] = true;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }



        //坟场不足以正常复活时的测试样例,小套娃，第一个死的坎格尔的复活的机械会给后面提供复活的来源
        public static void test13_1()
        {
            Pool u = new Pool(new 鱼人斥候());
            Pool d = new Pool(new 百变泽鲁斯(),new 爆爆机器人_金色(), new 百变泽鲁斯() ,new 坎格尔的学徒(), new 坎格尔的学徒_金色());
            for (int i = 0; i < 3; i++)
            {
                d.places[i].Skills[2] = true;
                d.places[i].Health++;//这里代表buff过
            }
            u.places[0].Health = 200;
            u.places[0].Skills[0] = true;
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //测试：龙击杀以及回合开始触发的效果，以及不按照正常攻击顺序结算的随从触发的蜡烛骑士效果
        public static void test14()
        {
            Pool d = new Pool(new 红色雏龙(), new 红色雏龙(), new 龙人军官(), new 雕文护卫者(), new 雕文护卫者(), new 蜡烛骑士托瓦格尔(), new 蜡烛骑士托瓦格尔_金色());
            Pool u = new Pool(new 红色雏龙_金色(), new 雕文护卫者_金色(), new 龙人军官(), new 雕文护卫者(), new 雕文护卫者(), new 龙人军官(), new 蜡烛骑士托瓦格尔_金色());

            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //测试火焰传令官，会正确跳过亡语召唤和受伤害召唤的随从（比如安保），并且期间自己死亡后也可以触发超杀
        //可以预测这个安保应当是无法召唤一个衍生随从的（超杀队列中不结算死亡所以没有格子），上方仅剩一个损坏的傀儡。
        //同时蜡烛骑士应当正确+14/+14(因为7个随从均死于龙手)
        public static void test15()
        {
            Pool d = new Pool(new 火焰传令官_金色(),new 蜡烛骑士托瓦格尔());
            Pool u = new Pool(new 虚空行者(), new 安保巡游者(),new 麦田傀儡(),new 融合怪(), new 融合怪(), new 融合怪(), new 融合怪());
            Board myBoard = new Board(true, d, u);
            u.places[1].Health = 3;
            myBoard.Execute(false);
            Console.ReadKey();
        }

        //用来测试小鬼妈妈，小鬼妈妈召唤，然后变成嘲讽。卡德加触发的是召唤的扳机，在两者之间，所以复制的应当没有嘲讽。
        //这个例子说明本模拟器正确实现了这一点。
        public static void test16()
        {
            Pool d = new Pool(new 小鬼妈妈(),new 卡德加());
            Pool u = new Pool(new 小鬼妈妈_金色());
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(false);
            Console.ReadKey();
        }


        //用来测试改进后的aoe，无论钴制卫士和安保如何摆放，都只会补一次盾，而如果原本钴制有盾是会补的,因为破盾的同时受伤，但安保受伤后才会召唤，召唤了才会补盾。所以是破盾后补盾，63圣盾
        public static void test17()
        {
            Pool d = new Pool(new 安保巡游者(), new 钴制卫士(),new 安保巡游者());
            Pool u = new Pool(new 洞穴多头蛇());
            u.places[0].SetValue(2,12);
            //添加这行代码来查看上面说的效果
            //d.places[1].SetValue(6, 3, "圣盾");
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(true);
            Console.ReadKey();
        }

        //同样用来测试新做的aoe
        //两条胖头鱼,其中一个有盾，那么打任何一个都会剩下一个有盾的（请自行分析）
        public static void test18_1()
        {
            Pool d = new Pool(new 鲭鱼圣者(), new 鲭鱼圣者());
            Pool u = new Pool(new 蹒跚的食尸鬼());
            u.places[0].SetValue(1, 1);
            d.places[1].SetValue(8, 4, "圣盾");
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(true);
            Console.ReadKey();
        }

        //承接上文，如果两个都有盾呢，那么触发的时候两个一起补盾。fgnb!
        public static void test18_2()
        {
            Pool d = new Pool(new 鲭鱼圣者(), new 鲭鱼圣者());
            Pool u = new Pool(new 死神4000型());
            d.places[0].SetValue(8, 4,"圣盾");
            d.places[1].SetValue(8, 4, "圣盾");
            Board myBoard = new Board(true, d, u);
            myBoard.Execute(true);
            Console.ReadKey();
        }


        public static void test19()
        {
            Pool d = new Pool(new 鲭鱼圣者(), new 鲭鱼圣者());
            Pool u = new Pool(new 鲭鱼圣者(),new 鲭鱼圣者());
            d.places[0].SetValue(8, 4, "圣盾");
            u.places[1].SetValue(8, 4, "圣盾");
            Board b = new Board(true, d, u);
            Board c = b.Copy();
            c.Debug = true;
            b.Execute(false);
            c.Execute(false);
            Console.ReadKey();
        }
    }
}
